package mobi.zeedev.flyingsaucer.common.WebQueryModule.impl;

import com.google.inject.Inject;
import com.google.inject.Singleton;
import com.google.inject.name.Named;
import mobi.zeedev.flyingsaucer.common.WebQueryModule.interfaces.IBeerWebQuery;
import org.apache.http.*;
import org.apache.http.client.CookieStore;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.params.ConnManagerParams;
import org.apache.http.conn.params.ConnPerRouteBean;
import org.apache.http.conn.routing.HttpRoute;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.cookie.Cookie;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpParams;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * User: James
 * Date: 1/4/11
 * Time: 3:47 AM
 */
@Singleton
public class ContinuousBeerWebQuery implements IBeerWebQuery {

    public static final int HTTP_STATUS_OK = 200;
    public static final int HTTP_STATUS_REDIRECT = 302;

    @Inject
    @Named("PRINT_DEBUG_STATEMENTS")
    protected Boolean PRINT_DEBUG_STATEMENTS;

    DefaultHttpClient client;

    @Inject
    public ContinuousBeerWebQuery() {
        initClient();
    }

    //XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    //  WebQuery Methods
    //XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

    private void initClient() {

        HttpParams params = new BasicHttpParams();
        // Increase max total connection to 200
        ConnManagerParams.setMaxTotalConnections(params, 200);
        // Increase default max connection per route to 20
        ConnPerRouteBean connPerRoute = new ConnPerRouteBean(20);
        // Increase max connections for localhost:80 to 50
        HttpHost beerKnurd = new HttpHost("www.beerknurd.com", 80);
        connPerRoute.setMaxForRoute(new HttpRoute(beerKnurd), 50);
        ConnManagerParams.setMaxConnectionsPerRoute(params, connPerRoute);

        SchemeRegistry schemeRegistry = new SchemeRegistry();
        schemeRegistry.register(
                new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
        schemeRegistry.register(
                new Scheme("https", SSLSocketFactory.getSocketFactory(), 443));

//        params.setBooleanParameter(ClientPNames.HANDLE_REDIRECTS, true);
//        params.setBooleanParameter(ClientPNames.ALLOW_CIRCULAR_REDIRECTS , true);
//        params.setBooleanParameter(ClientPNames.REJECT_RELATIVE_REDIRECT, false);

//        DefaultRedirectStrategy drs = new DefaultRedirectStrategy();

//        client.setRedirectStrategy(drs);


        ClientConnectionManager cm = new ThreadSafeClientConnManager(params, schemeRegistry);
        client = new DefaultHttpClient(cm, params);
    }

    private void shutdownClient() {
//        DefaultHttpClient httpclient = new DefaultHttpClient();
//        HttpGet httpget = new HttpGet("http://www.google.com/");
//        HttpResponse response = client.execute(httpget);
//        HttpEntity entity = response.getEntity();
//        System.out.println(response.getStatusLine());
//        if (entity != null) {
//            entity.consumeContent();
//        }
        client.getConnectionManager().shutdown();
    }

    @Override
    public void resetCookies() {
        client.getCookieStore().clear();
    }

    //    @Inject                 //@Named("cookieList") @Nullable
    @Override
    public void injectCookies(List<Cookie> cookieList) {
        if (cookieList == null) {
            return;
        }
        for (Cookie cookie : cookieList) {
            client.getCookieStore().addCookie(cookie);
        }
    }

    //XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    //  Data Access Methods
    //XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

    @Override
    public Result getUrlResultHttpPost(String url, UrlEncodedFormEntity postParamsIn, CookieStore csIn) throws HttpException, IOException {

        if (csIn != null) {
            injectCookies(csIn.getCookies());
        }

        HttpPost postRequest = new HttpPost(url);

        UrlEncodedFormEntity postEntity = postParamsIn;
        if (postEntity != null) {
            postRequest.setEntity(postEntity);
        }

        HttpResponse response = client.execute(postRequest);

        StatusLine status = response.getStatusLine();

        if (PRINT_DEBUG_STATEMENTS) {
            for (Header h : client.execute(postRequest).getAllHeaders()) {
                System.out.println("Headers: " + h.toString());
            }
            System.out.println("StatusLine: " + status);
        }

        checkStatusCode(status);

        HttpEntity entity = response.getEntity();

        ByteArrayOutputStream content = new ByteArrayOutputStream();

        entity.writeTo(content);
        entity.consumeContent();

        Result r = new Result();

        r.setStatusCode(status.getStatusCode());
        r.setContent(content);

//        List<Cookie> cookies = Collections.unmodifiableList(client.getCookieStore().getCookies());

        r.setCookies(client.getCookieStore().getCookies());
        r.setPostParams(postParamsIn);
        return r;
    }

    @Override
    public Result getUrlResultHttpGet(String url) throws HttpException, IOException {

        HttpGet getRequest = new HttpGet(url);

        HttpResponse response = client.execute(getRequest);


        StatusLine status = response.getStatusLine();

        if (PRINT_DEBUG_STATEMENTS) {
            for (Header h : client.execute(getRequest).getAllHeaders()) {
                System.out.println("Headers: " + h.toString());
            }
            System.out.println("StatusLine: " + status);
        }

        checkStatusCode(status);

        HttpEntity entity = response.getEntity();

        ByteArrayOutputStream content = new ByteArrayOutputStream();

        entity.writeTo(content);
        entity.consumeContent();


        Result r = new Result();

        r.setStatusCode(status.getStatusCode());
        r.setContent(content);

//        List<Cookie> cookies = Collections.unmodifiableList(client.getCookieStore().getCookies());
        r.setCookies(client.getCookieStore().getCookies());
        //r.postParams = postParamsIn;
        return r;
    }

    private void checkStatusCode(StatusLine status) throws HttpException {

        if (!(status.getStatusCode() == HTTP_STATUS_OK || status.getStatusCode() == HTTP_STATUS_REDIRECT)) {
            throw new HttpException("Invalid response from server: " +
                    status.toString());
        }

    }

    @Override
    public Result getUrlResultHttpGet(URL url) throws HttpException, IOException {
        return getUrlResultHttpGet(url.toString());
    }

    //XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    //  Utility Functions
    //XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

    @Override
    public UrlEncodedFormEntity generatePostParams(Map<String, String> params) throws UnsupportedEncodingException {
        //TODO this is duplicated from the other SingleBeerWebQuery
        List<NameValuePair> formparams = new ArrayList<NameValuePair>();
        formparams.add(new BasicNameValuePair("store", params.get("store")));
        formparams.add(new BasicNameValuePair("card_number", params.get("card_number")));
        formparams.add(new BasicNameValuePair("password", params.get("password")));
        formparams.add(new BasicNameValuePair("f", params.get("f")));
        if (params.get("mou") != null) {
            formparams.add(new BasicNameValuePair("mou", params.get("mou")));
        }
        formparams.add(new BasicNameValuePair("f", params.get("f")));
        UrlEncodedFormEntity postEntity = null;
        postEntity = new UrlEncodedFormEntity(formparams, "UTF-8");
        return postEntity;

    }

}
